﻿<?php

class ZFKiller_Correios_Frete {

	const E_SEDEX_COM_CONTRATO = 81019;
	const E_SEDEX_EXPRESS_COM_CONTRATO = 81035;
	const E_SEDEX_PRIORITARIO_COM_CONTRATO = 81027;
	const PAC_COM_CONTRATO = 41068;
	const PAC_SEM_CONTRATO = 41106;
	const SEDEX_10_SEM_CONTRATO = 40215;
	const SEDEX_A_COBRAR_SEM_CONTRATO = 40045;
	const SEDEX_A_COBRAR_COM_CONTRATO = 40126;
	const SEDEX_COM_CONTRATO = 40096;
	//const SEDEX_COM_CONTRATO = 40436;
	//const SEDEX_COM_CONTRATO = 40444;
	//const SEDEX_COM_CONTRATO = 40568;
	//const SEDEX_COM_CONTRATO = 40606;
	const SEDEX_HOJE_SEM_CONTRATO = 40290;
	const SEDEX_SEM_CONTRATO = 40010;
	const URL_WS = 'http://ws.correios.com.br/calculador/CalcPrecoPrazo.asmx?WSDL';

	/**
	 * Código administrativo junto à ECT
	 * 
	 * @var string
	 */
	private $_nCdEmpresa = '';

	/**
	 * Senha para acesso ao serviço
	 *
	 * @var string 
	 */
	private $_sDsSenha = '';

	/**
	 * Código do serviço
	 *
	 * @var array 
	 */
	private $_nCdServico = array();

	/**
	 * CEP de origem sem hífen
	 *
	 * @var numeric 
	 */
	private $_sCepOrigem;

	/**
	 * CEP de destino sem hífen
	 *
	 * @var numeric 
	 */
	private $_sCepDestino;

	/**
	 * Peso da encomenda em kg, incluindo sua embalagem
	 * 
	 * @var real 
	 */
	private $_nVlPeso = 0;

	/**
	 * Formato da encomenda.
	 * 1=Caixa/Pacote;
	 * 2=Prisma/Rolo;
	 * 
	 * @var int
	 */
	private $_nCdFormato = 1;

	/**
	 * Comprimento da encomenda em centimetros
	 *
	 * @var int
	 */
	private $_nVlComprimento = 16;

	/**
	 * Altura da encomenda em centimetros
	 *
	 * @var int
	 */
	private $_nVlAltura = 2;

	/**
	 * Largura da encomenda em centimetros
	 *
	 * @var int
	 */
	private $_nVlLargura = 11;

	/**
	 * Diametro da encomenda em centimetros
	 *
	 * @var int
	 */
	private $_nVlDiametro = 0;

	/**
	 * Indica se a encomenda será entregue com o serviço adicional mão própria
	 *
	 * @var boolean 
	 */
	private $_sCdMaoPropria = 'N';

	/**
	 * Indica se a encomenda será entregue com o serviço adicional valor declarado.
	 * Neste campo deve ser apresentado o valor declarado desejado, em R$.
	 *
	 * @var real 
	 */
	private $_nVlValorDeclarado = 0;

	/**
	 * Indica se a encomenda será entregue com o serviço adicional aviso de recebimento.
	 * S = Sim;
	 * N = Não
	 *
	 * @var type 
	 */
	private $_sCdAvisoRecebimento = 'N';
	public static $_servicos = array(
		self::E_SEDEX_COM_CONTRATO => 'e-SEDEX, com contrato',
		self::E_SEDEX_EXPRESS_COM_CONTRATO => 'e-SEDEX Express, com contrato',
		self::E_SEDEX_PRIORITARIO_COM_CONTRATO => 'e-SEDEX Prioritário, com contrato',
		self::PAC_COM_CONTRATO => 'PAC com contrato',
		self::PAC_SEM_CONTRATO => 'PAC sem contrato',
		self::SEDEX_10_SEM_CONTRATO => 'SEDEX 10, sem contrato',
		self::SEDEX_A_COBRAR_SEM_CONTRATO => 'SEDEX a Cobrar, sem contrato',
		self::SEDEX_A_COBRAR_COM_CONTRATO => 'SEDEX a Cobrar, com contrato',
		self::SEDEX_COM_CONTRATO => 'SEDEX com contrato',
		self::SEDEX_HOJE_SEM_CONTRATO => 'SEDEX Hoje, sem contrato',
		self::SEDEX_SEM_CONTRATO => 'SEDEX sem contrato',
	);
	public static $_servicosUser = array(
		self::E_SEDEX_COM_CONTRATO => 'Entrega expressa',
		self::E_SEDEX_EXPRESS_COM_CONTRATO => 'Entrega expressa',
		self::E_SEDEX_PRIORITARIO_COM_CONTRATO => 'Entrega expressa',
		self::PAC_COM_CONTRATO => 'Encomenda normal',
		self::PAC_SEM_CONTRATO => 'Encomenda normal',
		self::SEDEX_10_SEM_CONTRATO => 'Entrega expressa',
		self::SEDEX_A_COBRAR_SEM_CONTRATO => 'SEDEX a cobrar',
		self::SEDEX_A_COBRAR_COM_CONTRATO => 'SEDEX a cobrar',
		self::SEDEX_COM_CONTRATO => 'Entrega expressa',
		self::SEDEX_HOJE_SEM_CONTRATO => 'SEDEX Hoje, sem contrato',
		self::SEDEX_SEM_CONTRATO => 'Entrega expressa',
	);

	/**
	 * Adiciona um servico ao calculo do frete
	 * 
	 * @param int $servico 
	 */
	public function addServico($servico) {
		$this->_nCdServico[] = $servico;
	}

	/**
	 * Faz o calculo do frete
	 *
	 * @param string $returnFormat O tipo do retorno.
	 * Pode ser JSON ou Objeto.
	 * O padrão é Objeto.
	 * 
	 * @return array|json 
	 */
	public function calc($returnFormat = 'object') {
		$parms = new stdClass;
		$parms->nCdServico = join(',', $this->_nCdServico);
		$parms->nCdEmpresa = $this->_nCdEmpresa;
		$parms->sDsSenha = $this->_sDsSenha;
		$parms->StrRetorno = 'XML';

		$parms->sCepDestino = $this->_sCepDestino;
		$parms->sCepOrigem = $this->_sCepOrigem;
		$parms->nVlPeso = $this->_nVlPeso;

		$parms->nVlComprimento = $this->_nVlComprimento;
		$parms->nVlDiametro = $this->_nVlDiametro;
		$parms->nVlAltura = $this->_nVlAltura;
		$parms->nVlLargura = $this->_nVlLargura;

		$parms->nCdFormato = $this->_nCdFormato;
		$parms->sCdMaoPropria = $this->_sCdMaoPropria ? 'S' : 'N';
		$parms->nVlValorDeclarado = $this->_nVlValorDeclarado;
		$parms->sCdAvisoRecebimento = $this->_sCdAvisoRecebimento ? 'S' : 'N';

		//try {
		$soap = new SoapClient(self::URL_WS, array(
					'trace' => true,
					'exceptions' => true,
					'cache_wsdl' => WSDL_CACHE_DISK,
					'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP,
					'connection_timeout' => 1000,
					'features' => SOAP_SINGLE_ELEMENT_ARRAYS,
				));

		$resposta = $soap->CalcPrecoPrazo($parms);
		unset($soap);
		//} catch (Exception $e) {
		//	die('ERRO PARA CALCULAR');
		//	return false;
		//}
		$objeto = $resposta->CalcPrecoPrazoResult->Servicos->cServico;
		foreach($objeto as & $item) {
			$item->Valor = (int) strtr($item->Valor, array(','=>''));
			$item->ValorMaoPropria = (int) strtr($item->ValorMaoPropria, array(','=>''));
			$item->ValorAvisoRecebimento = (int) strtr($item->ValorAvisoRecebimento, array(','=>''));
			$item->ValorValorDeclarado = (int) strtr($item->ValorValorDeclarado, array(','=>''));
		}
		
		switch ($returnFormat) {
			case 'json':
				return json_encode($objeto);
				break;
			default:
				return $objeto;
				break;
		}
	}
	
	public function getServicoNome($cdServico) {
		return self::$_servicos[$cdServico];
	}

	/**
	 * Informa a altura (Deve ser informado em Centimetros)
	 * 
	 * @param int
	 */
	public function setAlturaCm($altura) {
		$this->_nVlAltura = (int) $altura;
	}

	/**
	 * Informa se o calculo será feito com aviso de recebimento
	 * 
	 * @param boolean
	 */
	public function setAvisoRecebimento($avisorecebimento) {
		if (is_bool($avisorecebimento)) {
			$this->_sCdAvisoRecebimento = $avisorecebimento;
		}
		else {
			$this->_sCdAvisoRecebimento = (($avisorecebimento == 'S') or ($avisorecebimento == '1'));
		}
	}
	
	public function setCdEmpresa($cdEmpresa) {
		$this->_nCdEmpresa = $cdEmpresa;
	}

	public function setCepDestino($cep) {
		$this->_sCepDestino = preg_replace('#([^0-9])#i', '', $cep);
	}

	public function setCepOrigem($cep) {
		$this->_sCepOrigem = preg_replace('#([^0-9])#i', '', $cep);
	}

	/**
	 * Informa o comprimento (Deve ser informado em Centimetros)
	 * 
	 * @param int
	 */
	public function setComprimentoCm($comprimento) {
		$this->_nVlComprimento = (int) $comprimento;
	}

	/**
	 * Informa o diametro (Deve ser informado em Centimetros)
	 * 
	 * @param int
	 */
	public function setDiametroCm($diametro) {
		$this->_nVlDiametro = (int) $diametro;
	}
	
	public function setDsSenha($dsSenha) {
		$this->_sDsSenha = $dsSenha;
	}

	/**
	 * Informa a largura (Deve ser informado em Centimetros)
	 * 
	 * @param int
	 */
	public function setLarguraCm($largura) {
		$this->_nVlLargura = (int) $largura;
	}

	/**
	 * Informa se deve calcular com o servico mão própria
	 * 
	 * @param boolean
	 */
	public function setMaoPropria($maopropria) {
		if (is_bool($maopropria)) {
			$this->_sCdMaoPropria = $maopropria;
		}
		else {
			$this->_sCdMaoPropria = (($maopropria == 'S') or ($maopropria == '1'));
		}
	}

	public function setPesoKg($peso) {
		$this->_nVlPeso = $peso;
	}
	
	/**
	 * Informa o peso em gramas
	 * 
	 * @param int
	 */
	public function setPesoG($peso) {
		$this->setPesoKg($peso / 1000);
	}

	/**
	 * Altera os servicos
	 * 
	 * @param int $servico 
	 */
	public function setServico(array $servico) {
		$this->_nCdServico = $servico;
	}

	/**
	 * Informa o valor declarado em centavos
	 * 
	 * @param int
	 */
	public function setValorDeclaradoC($valordeclarado) {
		$this->setValorDeclaradoR($valordeclarado / 100);
	}
	
	/**
	 * Informa o valor declarado em reais
	 * 
	 * @param real
	 */
	public function setValorDeclaradoR($valordeclarado) {
		$this->_nVlValorDeclarado = $valordeclarado;
	}

}